package com.bosssoft.boss_exam_web.Controller;


import com.bosssoft.boss_exam_core.common.Timer.CloseExamScheduler;
import com.bosssoft.boss_exam_core.enums.ResultCode;
import com.bosssoft.boss_exam_core.exception.*;
import com.bosssoft.boss_exam_core.util.web.ResponseUtil;
import com.bosssoft.boss_exam_core.validator.Order;
import com.bosssoft.boss_exam_core.validator.Sort;
import com.bosssoft.boss_exam_db.entity.*;
import com.bosssoft.boss_exam_db.model.vo.*;
import com.bosssoft.boss_exam_db.service.busines.*;
import com.bosssoft.boss_exam_web.common.annotation.LoginAdmin;
import com.bosssoft.boss_exam_web.common.annotation.LoginApplicant;
import com.bosssoft.boss_exam_web.model.dto.ExamPaperDTO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Validated
@Slf4j
@Api(value="考试控制器")
public class ExamController {

    // 引入试卷服务
    @Autowired
    private ExamService examService;

    // 引入管理员服务
    @Autowired
    private AdminService adminService;

    // 引入试卷服务
    @Autowired
    private ExamExamPaperService examExamPaperService;

    // 引入关闭考试定时
    @Autowired
    private CloseExamScheduler closeExamScheduler;

    // 引入应聘人服务
    @Autowired
    private ApplicantService applicantService;

    // 引入应聘人考试服务
    @Autowired
    private ApplicantExamService applicantExamService;

    @ApiOperation(value = "考试查询", notes = "可根据考试名称查询考试", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examName", value = "考试名称", dataType = "String", required = false, dataTypeClass = String.class),
            @ApiImplicitParam(name = "page", value = "当前页码", dataType = "String", required = false, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "limit", value = "每页显示条数", dataType = "String", required = false, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "sort", value = "排序依据", dataType = "String", required = false, dataTypeClass = String.class),
            @ApiImplicitParam(name = "order", value = "排序方式", dataType = "String", required = false, dataTypeClass = String.class)
    })
    @GetMapping("/admin/exam/list")
    public Object list(@LoginAdmin String adminId,
                       @RequestParam String examName,
                       @RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer limit,
                       @Sort @RequestParam(defaultValue = "add_time") String sort,
                       @Order @RequestParam(defaultValue = "desc") String order) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        //查询当前用户所在公司
        Company company = adminService.selectAdminBelongCompany(adminId);
        if(company==null){
            log.error("【严重警告】该管理员没有公司");
            throw new BusinessException("该管理员，没有归属公司");
        }
        PageInfo<ExamIsReleaseVO> examPageInfo = examService.queryByCondition(company, examName, page, limit, sort, order);
        if (examPageInfo == null) {
            log.error("【业余错误】，查询pageInfo为空");
            throw new QueryDataException();
        } else {
            Map<String, Object> data = new HashMap<>();
            data.put("total", examPageInfo.getTotal());
            data.put("items", examPageInfo.getList());
            return ResponseUtil.ok(data);
        }
    }

    @ApiOperation(value = "考试查询", notes = "PC端查看当前应聘者应聘公司的所有活跃的考试", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页码", dataType = "String", required = false, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "companyId", value = "应聘公司ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/pc/exam/queryExams")
    public Object pcExamList(@LoginApplicant String applicantId,
                             @RequestParam String companyId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        if (StringUtils.isEmpty(companyId)) {
            return ResponseUtil.badArgument();
        }
        List<Exam> exams = examService.queryExamByCompanyId(companyId);
        if (exams == null) {
            log.error("【业余错误】，查询该公司下的试卷错误");
            throw new QueryDataException();
        } else {
            return ResponseUtil.ok(exams);
        }
    }

    @ApiOperation(value = "考试查询", notes = "手机端查看当前应聘者应聘公司的所有活跃的考试", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页码", dataType = "String", required = false, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "companyId", value = "应聘公司ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/phone/queryExams")
    public Object phoneExamList(@LoginApplicant String applicantId,
                                @RequestParam String companyId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        if (StringUtils.isEmpty(companyId)) {
            return ResponseUtil.badArgument();
        }
        List<Exam> exams = examService.queryExamByCompanyId(companyId);
        if (exams == null) {
            log.error("【业余错误】，查询该公司下的试卷错误");
            throw new QueryDataException();
        } else {
            return ResponseUtil.ok(exams);
        }
    }

    @ApiOperation(value = "考试添加", notes = "添加考试", httpMethod = "POST", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "exam", value = "考试对象", dataType = "Exam", required = true, dataTypeClass = Exam.class),
    })
    @PostMapping("/admin/exam/create")
    public Object create(@LoginAdmin String adminId, @RequestBody Exam exam) {
        if (StringUtils.isEmpty(adminId)) {
            return ResponseUtil.unlogin();
        }
        //查询当前用户所在公司
        Company company = adminService.selectAdminBelongCompany(adminId);
        if(company==null){
            log.error("【严重警告】该管理员没有公司");
            throw new BusinessException("该管理员，没有归属公司");
        }
        // 发布考试
        exam.setCompanyId(company.getId());
        int recordNum = examService.saveNotNull(exam);
        // 开启关闭考试定时
        closeExamScheduler.startCron(exam.getEndTime(), exam);
        if (recordNum == 1) {
            return ResponseUtil.ok(exam);
        } else {
            log.error("【系统错误】 保存考试失败");
            throw new UpdateEntityException();
        }
    }

    @ApiOperation(value = "考试详细信息查询", notes = "可根据考试的ID查询详情", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "考试ID，非空", dataType = "String", required = true, dataTypeClass = String.class),
    })
    @GetMapping("/admin/exam/read")
    public Object read(@LoginAdmin String adminId, @NotNull Integer id) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        Exam exam = null;
        try {
            exam = examService.selectByKey(id);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            log.error("【系统错误】 反射操作异常" + e);
            throw new ReflectionException(ResultCode.SYSTEM_INNER_ERROR);
        } catch (Exception e) {
            log.error("【业务错误】 读取实体异常" + e);
            throw new QueryDataException();
        }
        return ResponseUtil.ok(exam);
    }


    @ApiOperation(value = "考试更新", notes = "更新考试", httpMethod = "POST", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "exam", value = "考试对象json，必须携带考试ID", dataType = "Exam", required = true, dataTypeClass = Exam.class),
    })
    @PostMapping("/admin/exam/update")
    public Object update(@LoginAdmin String adminId, @RequestBody Exam exam) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        int recordNum = examService.updateNotNull(exam);
        if (recordNum == 1) {
            return ResponseUtil.ok(exam);
        } else {
            log.error("【系统错误】 保存考试失败");
            throw new UpdateEntityException();
        }
    }

    @ApiOperation(value = "考试删除", notes = "可根据考试的ID逻辑删除考试", httpMethod = "POST", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "考试ID，非空", dataType = "String", required = true, dataTypeClass = String.class),
    })
    @PostMapping("/admin/exam/delete")
    public Object delete(@LoginAdmin String adminId, @RequestParam String id) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        Exam exam = new Exam();
        exam.setId(id);
        try {
            int i = examService.deleteForLogic(exam);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            log.error("【系统错误】 反射操作异常" + e);
            throw new ReflectionException(ResultCode.SYSTEM_INNER_ERROR);
        } catch (Exception e) {
            log.info("【业务错误】 逻辑删除考试异常" + e);
            throw new DeleteEntityException();
        }
        return ResponseUtil.ok();
    }

    @ApiOperation(value = "选择试卷", notes = "可根据岗位、难度、公司/集团开放条件查询试卷", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "jobId", value = "考试ID，非空", dataType = "String", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "examPaperLevel", value = "考试ID，非空", dataType = "String", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "flag", value = "考试ID，非空", dataType = "Integer", required = true, dataTypeClass = Integer.class),
    })
    @PostMapping("/admin/exam/fetchExamPaper")
    public Object read(@LoginAdmin String adminId, @RequestBody ExamPaperDTO examPaperDTO) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        List<ExamPaper> examPapers = null;
        try {
            Company company = adminService.selectAdminBelongCompany(adminId);
            examPapers = examService.queryExamPaperByCondition(company.getId(), company.getGroupId(), examPaperDTO.getJobId(), examPaperDTO.getExamLevel(), examPaperDTO.getFlag());
        } catch (Exception e) {
            log.error("【业务错误】 读取实体异常" + e);
            throw new QueryDataException();
        }
        return ResponseUtil.ok(examPapers);
    }


    @ApiOperation(value = "发布考试", notes = "为一场考试设置一份试卷，即阅卷官", httpMethod = "POST", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examExamPaper", value = "考试试卷关系记录", dataType = "ExamExamPaper", required = true, dataTypeClass = ExamExamPaper.class),
    })
    @PostMapping("/admin/exam/releaseExam")
    public Object releaseExam(@LoginAdmin String adminId, @RequestBody ExamExamPaper examExamPaper) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        int recordNum = examExamPaperService.insertExamExamPaper(examExamPaper);
        if (recordNum == 1) {
            return ResponseUtil.ok();
        } else {
            log.error("【系统错误】 保存考试失败");
            throw new UpdateEntityException();
        }
    }

    @ApiOperation(value = "参与考试", notes = "应聘者参与考试", httpMethod = "POST", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试ID", dataType = "String", required = true, dataTypeClass = String.class),
    })
    @PostMapping("/pc/exam/attendExam")
    public Object create(@LoginApplicant String applicantId, @RequestParam String examId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        try {
            Applicant applicant = applicantService.selectByKey(applicantId);
            if (applicant == null) {
                log.error("【非法访问】");
                throw new BusinessException("非法访问");
            }
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new BusinessException("反射操作异常");
        }
        // 发布考试
        int recordNum = applicantExamService.insertApplicantExam(examId, applicantId);
        if (recordNum == 1) {
            return ResponseUtil.ok();
        } else {
            return ResponseUtil.ok("不要重复提交");
        }
    }

    @ApiOperation(value = "考试查询", notes = "PC端查看当前应聘者参与的所有活跃的考试", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页码", dataType = "String", required = false, dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "companyId", value = "应聘公司ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/pc/exam/queryMyExams")
    public Object pcGetApplicantExamList(@LoginApplicant String applicantId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        List<ApplicantExamVO> exams = applicantExamService.queryExamByApplicant(applicantId);
        //过滤时间过期的考试
        List<ApplicantExamVO> applicantExamExamVOS = exams.stream().filter(applicantExamExamVO -> applicantExamExamVO.getEndTime().getTime() > System.currentTimeMillis()).collect(Collectors.toList());
        if (applicantExamExamVOS == null) {
            log.error("【业余错误】，查询该公司下的试卷错误");
            throw new QueryDataException();
        } else {
            return ResponseUtil.ok(applicantExamExamVOS);
        }
    }

    @ApiOperation(value = "考试查询", notes = "手机端查看当前应聘者参与的所有活跃的考试", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicantId", value = "应聘者ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/phone/exam/queryMyExams")
    public Object phoneGetApplicantExamList(@LoginApplicant String applicantId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        List<ApplicantExamVO> exams = applicantExamService.queryExamByApplicant(applicantId);
        //过滤时间过期的考试
        List<ApplicantExamVO> applicantExamExamVOS = exams.stream().filter(applicantExamExamVO -> applicantExamExamVO.getEndTime().getTime() > System.currentTimeMillis()).collect(Collectors.toList());
        if (applicantExamExamVOS == null) {
            log.error("【业余错误】，查询该公司下的试卷错误");
            throw new QueryDataException();
        } else {
            return ResponseUtil.ok(applicantExamExamVOS);
        }
    }

    @ApiOperation(value = "查询考试和试卷", notes = "PC端根据考试Id查询考试和试卷", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试Id", dataType = "String", required = false, dataTypeClass = String.class),

    })
    @GetMapping("/pc/exam/queryExamAndPaper")
    public Object getExamAndExamPaper(@LoginApplicant String applicantId, @RequestParam String examId) {
        if (StringUtils.isEmpty(applicantId)) {
            return ResponseUtil.unlogin();
        }
        if (StringUtils.isEmpty(examId)) {
            return ResponseUtil.badArgument();
        }
        List<ExamExamPaperVO> exams = examService.getExamAndPaperById(examId);
        // todo 此处暂未做时间过期过滤
        if (exams == null) {
            log.error("【业余错误】，查询该公司下的试卷错误");
            throw new QueryDataException();
        } else {
            return ResponseUtil.ok(exams);
        }
    }

    @ApiOperation(value = "查询考试情况", notes = "查询某场考试的个人得分", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examCode", value = "考试批次", dataType = "String", required = true, dataTypeClass = String.class),
    })
    @GetMapping("/admin/exam/queryExamScore")
    public Object queryExamScore(@LoginAdmin String adminId,
                                 @RequestParam String examCode,
                                 @RequestParam(defaultValue = "1") Integer page,
                                 @RequestParam(defaultValue = "10") Integer limit,
                                 @Sort @RequestParam(defaultValue = "add_time") String sort,
                                 @Order @RequestParam(defaultValue = "desc") String order) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        PageHelper.startPage(page, limit).setOrderBy("applicant_question_score." + sort + " " + order);
        List<ApplicantTotalScoreVO> applicantTotalScoreVOS = examService.queryExamScoreByExamCod(examCode);
        PageInfo<ApplicantTotalScoreVO> examIsReleaseVOPageInfo = PageInfo.of(applicantTotalScoreVOS);
        if (examIsReleaseVOPageInfo == null) {
            log.error("【业余错误】，查询pageInfo为空");
            throw new QueryDataException();
        } else {
            Map<String, Object> data = new HashMap<>();
            data.put("total", examIsReleaseVOPageInfo.getTotal());
            data.put("items", examIsReleaseVOPageInfo.getList());
            return ResponseUtil.ok(data);
        }
    }


    @ApiOperation(value = "查看考试情况", notes = "根据题目科目查询考生试卷分布", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试ID", dataType = "String", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "applicantId", value = "应聘人ID", dataType = "String", required = true, dataTypeClass = String.class),
    })

    @GetMapping("/admin/exam/queryApplicantExamDetail")
    public Object queryExamScoreBySubject(@LoginAdmin String adminId,
                                          @RequestParam String examId,
                                          @RequestParam String applicantId) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        List<QuestionSubjectScoreVO> queryExamScoreBySubject = examService.queryExamScoreBySubject(examId, applicantId);

        List<QuestiontypeScoreVO> questiontypeScoreVOS = examService.queryExamScoreByQuestionType(examId, applicantId);

        HashMap<String, Object> data = new HashMap<>();
        // totallScore为总分
        data.put("typeScore", questiontypeScoreVOS);
        // subjectScore 科目分数
        data.put("subjectScore", queryExamScoreBySubject);
        return ResponseUtil.ok(data);
    }


    @ApiOperation(value = "查看试卷分数分布情况", notes = "根据某场考试查询试卷中分数分布情况", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/admin/exam/queryExamTotalScoreDistribuild")
    public Object queryExamTotalScoreBySubject(@LoginAdmin String adminId, @RequestParam String examId) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        if (StringUtils.isEmpty(examId)) {
            return ResponseUtil.badArgument();
        }
        List<SubjectTotalScoreVO> questionSubjectScoreVOS = this.examService.queryExamTotalScoreBySubject(examId);
        List<QuestiontypeTotalScoreVO> questiontypeTotalScoreVOS = this.examService.queryExamTotalScoreByQuestionType(examId);
        HashMap<String, Object> data = new HashMap<>();
        // totallScore为总分
        data.put("questionTypeTotalScoreArr", questiontypeTotalScoreVOS);
        // subjectScore 科目分数
        data.put("subjectTotalScoreArr", questionSubjectScoreVOS);
        return ResponseUtil.ok(data);
    }

    @ApiOperation(value = "查看应聘人科目得分和考试科目分数占比情况", notes = "根据某场考试查询试卷中科目考核占比情况", httpMethod = "GET", response = Object.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试ID", dataType = "String", required = true, dataTypeClass = String.class)
    })
    @GetMapping("/admin/exam/queryApplicantExamDistribuild")
    public Object queryApplicantExamDistribuild(@LoginAdmin String adminId, @RequestParam String examId,@RequestParam String applicantId) {
        if (adminId == null) {
            return ResponseUtil.unlogin();
        }
        if (StringUtils.isEmpty(examId)) {
            return ResponseUtil.badArgument();
        }
        List<QuestionSubjectScoreVO> queryExamScoreBySubject = examService.queryExamScoreBySubject(examId, applicantId);
        List<SubjectTotalScoreVO> subjectTotalScoreVOS = this.examService.queryExamTotalScoreBySubject(examId);
        HashMap<String, Object> data = new HashMap<>();
        // totallScore为总分
        data.put("applicantSubjectTotalScoreArr", queryExamScoreBySubject);
        // subjectScore 科目分数
        data.put("subjectTotalScoreArr", subjectTotalScoreVOS);
        return ResponseUtil.ok(data);
    }

}

